package meteocal.gui;

import java.io.Serializable;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
import meteocal.business.boundary.BadWeatherFacade;
import meteocal.business.boundary.EventFacade;
import meteocal.business.boundary.NotificationFacade;
import meteocal.business.boundary.UserFacade;
import meteocal.business.control.DateUtils;
import meteocal.business.control.ForecastChecker;
import meteocal.business.entity.Event;
import meteocal.business.security.entity.User;
import org.primefaces.event.SelectEvent;

/**
 *
 * @author luana
 */

@Named
@ViewScoped
public class EventBean implements Serializable{
    
    private Event event;

    @Inject
    ShowCalendarBean showCalendarBean;
    
    @Inject 
    Principal principal;
    
    @EJB 
    EventFacade ef;
    
    @EJB
    UserFacade uf; 
    
    @EJB
    BadWeatherFacade bd;
    
    @EJB
    ForecastChecker fc;
            
    @EJB
    NotificationFacade nf;
   
    private DateUtils dateManager;
   
    
    private Date stDate_lowerBound;
    private Date enDate_lowerBound;
    private Date stDate;
    private Date enDate;
    private Date stTime;
    private Date enTime;
    
    /**
     * Username of the candidate user to be added to invited users.
     */
    private String pendingUser;
    
    /**
     * List of the invited users (pending list).
     */
    private Collection<User> invitations;
    private Collection<User> partecipatingUsers;
    
    /**
     * List of Weather Categories.
     */
    private List<String> weatherList; 
    
    /**
     * Selected Bad Weather conditions.
     */
    private String[] badSelected;
    
    public EventBean(){  
        
    }
    
    @PostConstruct
    public void init(){
        dateManager = new DateUtils();
        stDate_lowerBound = dateManager.currentDay();
        enDate_lowerBound = dateManager.currentDay();
        
        invitations = new ArrayList<User>();
        partecipatingUsers = new ArrayList<User>();
        
        weatherList = new ArrayList<String>();
        weatherList.add("Thunderstorm");
        weatherList.add("Drizzle");
        weatherList.add("Rain");
        weatherList.add("Snow");
        weatherList.add("Atmosphere");
        weatherList.add("Clouds");
        weatherList.add("Extreme");
        
        

    }
    

    public Event getEvent() {
        if (event == null) {
            event = new Event();
        }
        return event;
    }
    
    public void setEvent(Event event) {
        this.event = event;
    }
  
    public String addEvent (){
        //Input validation
        if(stDate.compareTo(enDate)==0){
            if(enTime.before(stTime)==true){
                generateMessage("Invalid Ending Time! The event should ends after it starts");
                return null;
            }
        }
        
        Date evStart = new Date(stDate.getTime()+stTime.getTime());
        if(evStart.before(dateManager.currentDay())){
            generateMessage("Invalid Starting Time! The event should starts before now");
            return null;
        }
        
        // Creation of the new event
        
        event.setStarting_date(stDate);
        event.setEnding_date(enDate);
        event.setStartingTime(stTime);
        event.setEndingTime(enTime);
        event.setPendingUsers(invitations);
        ef.create(event);
        /**
         * type notification = 1
         * Notification [1]= send notification to participate to an event
         */
        for (User u: invitations){
           nf.create(event, u.getUsername(), 1);
        }
        
        if(badSelected != null){
            for(int i=0; i<badSelected.length; i++){
                bd.create(event,badSelected[i]);
            }
        } 
        return showCalendarBean.createEvent(event);
    }
    
    public void generateMessage(String message) {
        FacesContext context = FacesContext.getCurrentInstance();
        context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error!",message) );
    }
   
    /**
     * Before modifiyng an event a notification must be send to
     * users invited to that event.
     * In this case the type of the notification is 3
     * @return 
     */
    public String modifyEvent(){
        
        //Only the creator can modify
        if(!event.getCreator().getUsername().equals(principal.getName())){
            generateMessage("You are not the creator of this event!");
                return null;
        }
        
        //Input validation
        if(event.getStarting_date().compareTo(event.getEnding_date())==0){
            if(event.getEndingTime().before(event.getStartingTime())==true){
                generateMessage("Invalid Ending Time! The event should ends after it starts");
                return null;
            }
        }
        
        Date evStart = new Date(event.getStarting_date().getTime()+event.getStartingTime().getTime());
        if(evStart.before(dateManager.currentDay())){
            generateMessage("Invalid Starting Time! The event should starts before now");
            return null;
        }
        
        Collection<User> invited;
        invited = event.getParticipants();
        for(User u: invited){
           nf.create(event, u.getUsername(), 3);
        }
        showCalendarBean.deleteEvent(event);
        ef.updateEvent(event);
        return showCalendarBean.createEvent(event);
    }
    
    
    /**
     * When the starting date has been selected, this method makes sure the event ending date won't be
     * before the starting one.
     */
        public void changeEnDate_lowerBound(){
  
        enDate_lowerBound = stDate;
    }
        
    /**
    *  When the user inputs a string, this method is called to offer suggestons isers that matches the string;
    *  The user then can pick one and invite him to the event he's creating.
     * @param query
     * @return The matching users 
    */
      public List<User> completeUser(String query) {
            List<User> users = new ArrayList<User>();
            users = uf.searchUserUsername(query);
            return users; 
        }

        
    /**
     * Adds to the pending users list the one currently selected by the user.
     * @param event
     */
        public void addToPending(SelectEvent event){
            String username = event.getObject().toString();
            User user = uf.find(username);
            try{
                
                invitations.add(user);
                
            } catch(NullPointerException e){
                System.out.println(e.getMessage());
            }
            
            
        }
   
   
     // Getters and Setters
     
    
    public String getName() {
        return ef.getEvent().getName();
    }
    
    
    public Date getStTime() {
        return stTime;
    }

    public void setStTime(Date stTime) {
        this.stTime = stTime;
    }

    public Date getEnTime() {
        return enTime;
    }

    public void setEnTime(Date enTime) {
        this.enTime = enTime;
    }
    public String getCity() {
        return ef.getEvent().getPlace();
    }
    
    public Date getEnDate_lowerBound() {
        return enDate_lowerBound;
    }
    
    
    public Date getStDate_lowerBound() {
        return stDate_lowerBound;
    }

    public void setStDate_lowerBound(Date stDate_lowerBound) {
        this.stDate_lowerBound = stDate_lowerBound;
    }

    public void setEnDate_lowerBound(Date enDate_lowerBound) {
        this.enDate_lowerBound = enDate_lowerBound;
    }

    public Date getStDate() {
        return stDate;
    }

    public void setStDate(Date stDate) {
        this.stDate = stDate;
    }

    public Date getEnDate() {
        return enDate;
    }

    public void setEnDate(Date enDate) {
        this.enDate = enDate;
    }

   
    public String getDescription(){
        return ef.getEvent().getDescription();
    }
    
    public Date getStartingTime(){
        return ef.getEvent().getStartingTime();
    }
    
    public Date getEndingTime(){
        return ef.getEvent().getEndingTime();
    }
    
    public boolean getTypePlace(){
        return ef.getEvent().getType();
    }

    public String getPendingUser() {
        return pendingUser;
    }

    public void setPendingUser(String pendingUser) {
        this.pendingUser = pendingUser;
    }

    public Collection<User> getInvitations() {
        return invitations;
    }

    public void setInvitations(Collection<User> invitations) {
        this.invitations = invitations;
    }

    public Collection<String> getWeatherList() {
        return weatherList;
    }

    public void setWeatherList(List<String> weatherList) {
        this.weatherList = weatherList;
    }

    public String[] getBadSelected() {
        return badSelected;
    }

    public void setBadSelected(String[] badSelected) {
        this.badSelected = badSelected;
    }  
}
      

